测试Change Dectection¶
准备¶
先改造一下Login组件,增加一个Logout按钮
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | @Component({ selector: 'app-login', template: ` <a> <span *ngIf="needsLogin()">Login</span> <span *ngIf="!needsLogin()">Logout</span> </a> ` }) export class LoginComponent { constructor(private auth: AuthService) { } needsLogin() { return !this.auth.isAuthenticated(); } } |
测试类内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | /* tslint:disable:no-unused-variable */ import {TestBed, async, ComponentFixture} from '@angular/core/testing'; import {LoginComponent} from './login.component'; import {AuthService} from "./auth.service"; import {DebugElement} from "@angular/core"; import {By} from "@angular/platform-browser"; describe('Component: Login', () => { let component: LoginComponent; let fixture: ComponentFixture<LoginComponent>; let authService: AuthService; let el: DebugElement; beforeEach(() => { // refine the test module by declaring the test component TestBed.configureTestingModule({ declarations: [LoginComponent], providers: [AuthService] }); // create component and test fixture fixture = TestBed.createComponent(LoginComponent); // get test component from the fixture component = fixture.componentInstance; // UserService provided to the TestBed authService = TestBed.get(AuthService); // get the "a" element by CSS selector (e.g., by class name) el = fixture.debugElement.query(By.css('a')); }); }); |
- 引入了DebugElement、By.
- 定义了一个DebugElement类型的el 变量,并通过fixture获取DOM对象的引用: Login、Logout的按钮
- 通过 el.nativeElement.textContent.trim() 我们可以获取该DOM对象的文本内容
检测内容变化¶
第一个测试用例
1 2 3 | it('login button hidden when the user is authenticated', () => { expect(el.nativeElement.textContent.trim()).toBe(''); }); |
我们期望其内容为空,是因为Angular首次加载时并未感知内容变化。 Fixture是对测试组件的一个包装,我们可以控制它感知内容变化。 如何实现呢?答案是fixture的detectChanges方法。
1 2 3 4 5 | it('login button hidden when the user is authenticated', () => { expect(el.nativeElement.textContent.trim()).toBe(''); fixture.detectChanges(); expect(el.nativeElement.textContent.trim()).toBe('Login'); }); |
一旦调用detchChanges方法,Angular将检测属性绑定。AuthService的authenticated方法默认返回的是false,所有应该显示Login.
现在通过spy模拟AuthService返回true:
1 2 3 4 5 6 7 | it('login button hidden when the user is authenticated', () => { expect(el.nativeElement.textContent.trim()).toBe(''); fixture.detectChanges(); expect(el.nativeElement.textContent.trim()).toBe('Login'); spyOn(authService, 'isAuthenticated').and.returnValue(true); expect(el.nativeElement.textContent.trim()).toBe('Login'); }); |
此时虽然AuthService返回true,但是没有调用detectChanges,组件的view不会更新,a标签内容依然为Login。如果我们再次调用detectChanges则可以看到内容的变化。
1 2 3 4 5 6 7 8 9 | it('login button hidden when the user is authenticated', () => { expect(el.nativeElement.textContent.trim()).toBe(''); fixture.detectChanges(); expect(el.nativeElement.textContent.trim()).toBe('Login'); spyOn(authService, 'isAuthenticated').and.returnValue(true); expect(el.nativeElement.textContent.trim()).toBe('Login'); fixture.detectChanges(); expect(el.nativeElement.textContent.trim()).toBe('Logout'); }); |